In general, profiling refers to a collection of techniques that allow a programmer to obtain information about the execution flow of a software program. For example, a programmer may use profiling to learn information about a program such as which calls are made during execution of the program, statistics regarding the calls (e.g., durations, frequencies, etc.), or any other information regarding the execution of the program. In some cases, a program may be profiled by taking random samples of the program counter of the executing program and deriving statistics from the samples. In other cases, programmatic “hooks” may be inserted into the program itself, to capture information regarding the execution flow of the program. However, this process, also known as instrumenting, can change the execution characteristics of the program, as the instrumented code will also need to be executed.
Profiling that captures the amount and location of memory allocation is an important tool for a programmer who wishes to reduce memory footprint or discover the source of memory leaks in a software system. When some memory allocation operations occur in common subroutines, the information captured may be of insufficient help to the programmer. In such cases, the programmer needs to know the “provenance” of the memory allocation, i.e., the sequence of events that lead to it.
In traditional, stack-based languages and runtimes, capturing provenance information is fairly straightforward using standard profiling techniques. In particular, the current execution stack itself is the provenance. However, these techniques are not as effective in systems that use asynchronous message passing. Instead, in an asynchronous message passing system, the stack information available to the memory profiling instrumentation contains only that information which has accumulated since the most recent input. This means that the true source of an execution event of interest (e.g., a memory/object allocation, etc.) may be obscured.